package dbtool

import (
	"fmt"
	"gorm.io/gorm"
	"local.public/innerpkg/logger"
	"local.public/params"
	"local.public/utils"
	"reflect"
	"strconv"
	"strings"
)

func HandleOrder(gormdb *gorm.DB, u *params.PagingParams) {
	if u.Order != "" {
		orderFieldArr := strings.Split(u.Order, ",")
		for _, oneOrderField := range orderFieldArr {
			sTmpOrderField := strings.Trim(oneOrderField, " ")
			if strings.HasPrefix(sTmpOrderField, "-") {
				sTmpOrderField = sTmpOrderField[1:]
				gormdb = gormdb.Order(sTmpOrderField + " desc")
			} else {
				gormdb = gormdb.Order(sTmpOrderField + " asc")
			}
		}
	}
}

func getGormTagColumnName(sGormTag string) string {
	setting := map[string]string{}
	if sGormTag == "" {
		return ""
	}

	tags := strings.Split(sGormTag, ";")
	for _, value := range tags {
		v := strings.Split(value, ":")
		k := strings.TrimSpace(strings.ToUpper(v[0]))
		if len(v) >= 2 {
			setting[k] = strings.Join(v[1:], ":")
		} else {
			setting[k] = k
		}
	}
	//fmt.Printf("setting %+v \n", setting)
	columnValue, ok := setting["COLUMN"]
	if ok {
		return columnValue
	} else {
		return ""
	}
}

func GetModelFieldDef(destJsonField string, u interface{}) (bool, *params.ModelFieldDef) {
	ok := false
	sDestJsonField := destJsonField
	lenJsonField := len(destJsonField)
	if lenJsonField > 2 {
		last2char := sDestJsonField[lenJsonField-2 : lenJsonField]
		hasHash := utils.InStringArr(last2char, []string{"#0", "#1", "#2", "#3", "#4", "#5", "#6", "#7", "#8", "#9"})
		if hasHash {
			sDestJsonField = sDestJsonField[0 : lenJsonField-2]
		}
	}

	pFdInfo := &params.ModelFieldDef{
		FieldName: "",
		FieldType: "",
		JsonField: sDestJsonField,
		DbField:   "",
	}

	typ := reflect.TypeOf(u)
	val := reflect.ValueOf(u) //获取reflect.Type类型
	kd := val.Kind()          //获取到a对应的类别

	if kd == reflect.Ptr {
		typ = typ.Elem()
		val = val.Elem()
		//v1 := reflect.New(typ)  //重新构造一个结构体实例
		//val = v1.Elem()
		kd = val.Kind() //获取到a对应的类别
	}

	if kd != reflect.Struct {
		fmt.Println("expect struct")
		return false, pFdInfo
	}
	//获取到该结构体有几个字段
	num := val.NumField()
	//fmt.Printf("该结构体有%d个字段\n", num) //4个

	//遍历结构体的所有字段
	for i := 0; i < num; i++ {
		//获取到struct标签，需要通过reflect.Type来获取tag标签的值
		sFieldName := typ.Field(i).Name
		jsonTagVal := typ.Field(i).Tag.Get("json")
		gormTagVal := typ.Field(i).Tag.Get("gorm")
		gormColumnName := getGormTagColumnName(gormTagVal)
		//fmt.Printf("Field %d:FieldName %s 值=%v tagVal=%s kind=%v columnName=%v \n", i, sFieldName, val.Field(i), jsonTagVal, val.Field(i).Kind(), gormColumnName)

		//如果该字段有tag标签就显示，否则就不显示
		if jsonTagVal == sDestJsonField || jsonTagVal == sDestJsonField+",omitempty" {
			pFdInfo.FieldName = sFieldName
			pFdInfo.DbField = gormColumnName
			switch val.Field(i).Kind() {
			case reflect.Struct:
				//fieldtyp := val.Field(i).Type().Name()
				if val.Field(i).Type().String() == "time.Time" {
					pFdInfo.FieldType = "time.Time"
					break
				} else {
					fmt.Println("val.Field(i).Type().Name() ", val.Field(i).Type().Name(), " val.Field(i).Type().String() ", val.Field(i).Type().String())
					pFdInfo.FieldType = "struct"
					break
				}
			case reflect.String:
				pFdInfo.FieldType = "string"
				break
			case reflect.Bool:
				pFdInfo.FieldType = "bool"
				break
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				pFdInfo.FieldType = "int"
				break
			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
				pFdInfo.FieldType = "int"
				break
			case reflect.Float32, reflect.Float64:
				pFdInfo.FieldType = "float"
				break
			default:
				break
			}

			ok = true
			//fmt.Printf("Field %d:值=%v tagVal=%s kind=%v \n",i,val.Field(i),tagVal,val.Field(i).Kind())
			break
		} else if val.Field(i).Kind().String() == "struct" { //如果是未知的结构体需要递归查找
			st := typ.Field(i).Type
			v1 := reflect.New(st)
			v2 := v1.Elem()
			bFind2, pFdInfo2 := GetModelFieldDef(sDestJsonField, v2.Interface())

			if bFind2 {
				ok = bFind2
				pFdInfo = pFdInfo2
				//fmt.Println("bFind2,sResultType2 is ",sResultType2)
				break
			} else {
				continue
			}
		}
	}
	return ok, pFdInfo
}

func CommonGetRows(engine *gorm.DB, pModel interface{}, headerparam *params.HeaderParam, qryparam *map[string]interface{}) (rsp *params.QueryListRspParam, err error) {

	devRows, totalCnt, err1 := InnerCommonGetRows(engine, pModel, headerparam, qryparam)
	if err1 != nil {
		return nil, err
	}

	iPageSize := 0
	iPageNum := 0
	for sJsonField, matchValue := range *qryparam {
		if sJsonField == "pagesize" {
			iPageSize = int(matchValue.(float64))
			continue
		}
		if sJsonField == "pagenum" {
			iPageNum = int(matchValue.(float64))
			continue
		}
		continue
	}
	rsp = &params.QueryListRspParam{
		PageNum:  iPageNum,
		PageSize: iPageSize,
		Total:    totalCnt,
		List:     devRows,
	}
	return
}

func InnerCommonGetRows(engine *gorm.DB, pModel interface{}, headerparam *params.HeaderParam, qryparam *map[string]interface{}) (rows interface{}, totalcnt int64, err error) {
	mEngine := engine
	var gormdb *gorm.DB
	gormdb = mEngine.Model(pModel)

	iPageSize := 0
	iPageNum := 0
	sOrder := ""

	fmt.Printf("%+v \n", qryparam)
	for sJsonField, matchValue := range *qryparam {
		if sJsonField == "pagesize" {
			iPageSize = int(matchValue.(float64))
			continue
		}
		if sJsonField == "offset" {
			iPageNum = int(matchValue.(float64))
			continue
		}
		if sJsonField == "order" {
			sOrder = matchValue.(string)
			continue
		}
		if sJsonField == "datefrom" {
			if matchValue.(string) == "" {
				continue
			}
			arr := strings.Split(matchValue.(string), ",")
			if len(arr) == 2 { //说明在matchvalue中指定了字段
				gormdb = gormdb.Where(arr[0]+" >= ? ", arr[1])
				continue
			}

			bFind4, _ := GetModelFieldDef("create_time", pModel)
			if bFind4 {
				gormdb = gormdb.Where(" DATE_FORMAT(create_time,'%Y-%m-%d') >= ? ", matchValue.(string))
				continue
			}
			continue
		}
		if sJsonField == "dateto" {
			if matchValue.(string) == "" {
				continue
			}
			arr := strings.Split(matchValue.(string), ",")
			if len(arr) == 2 { //说明在matchvalue中指定了字段
				gormdb = gormdb.Where(arr[0]+" <= ? ", arr[1])
				continue
			}
			bFind4, _ := GetModelFieldDef("create_time", pModel)
			if bFind4 {
				gormdb = gormdb.Where(" DATE_FORMAT(create_time,'%Y-%m-%d') <= ? ", matchValue.(string))
				continue
			}
			continue
		}

		bFind2, pFdInfo := GetModelFieldDef(sJsonField, pModel)
		if !bFind2 {
			continue
		}
		fmt.Printf("%+v \n", pFdInfo)
		sDBField := pFdInfo.DbField
		sFieldType := pFdInfo.FieldType

		if sFieldType == "string" {
			sMatchValue := matchValue.(string)
			if sMatchValue == "" {
				continue
			}

			if strings.HasSuffix(sJsonField, "id") {
				gormdb = gormdb.Where("`"+sDBField+"` = ? ", sMatchValue)
			} else {
				if strings.HasPrefix(sMatchValue, "=") {
					sMatchValue = strings.ToLower(sMatchValue[1:])
					gormdb = gormdb.Where("`"+sDBField+"` = ? ", sMatchValue)
				} else {
					gormdb = gormdb.Where("`"+sDBField+"` like ? ", "%"+matchValue.(string)+"%")
				}

			}
		} else if sFieldType == "int" {
			if sMatchValue, ok := matchValue.(string); ok {
				if strings.HasPrefix(sMatchValue, ">=") || strings.HasPrefix(sMatchValue, "<=") {
					sRealMatchValue := strings.TrimSpace(sMatchValue[2:])
					if sRealMatchValue == "" {
						continue
					}
					iMatchValue, err2 := strconv.Atoi(sRealMatchValue)
					if err2 != nil {
						logger.Error(sFieldType + "类型的" + sJsonField + "字段的输入条件不合法！" + matchValue.(string))
					}
					gormdb = gormdb.Where("`"+sDBField+"` "+sMatchValue[0:2]+" ? ", iMatchValue)
				} else if strings.HasPrefix(sMatchValue, "=") || strings.HasPrefix(sMatchValue, ">") || strings.HasPrefix(sMatchValue, "<") {
					sRealMatchValue := strings.TrimSpace(sMatchValue[1:])
					if sRealMatchValue == "" {
						continue
					}
					iMatchValue, err2 := strconv.Atoi(sRealMatchValue)
					if err2 != nil {
						logger.Error(sFieldType + "类型的" + sJsonField + "字段的输入条件不合法！" + matchValue.(string))
					}
					gormdb = gormdb.Where("`"+sDBField+"` "+sMatchValue[0:1]+" ? ", iMatchValue)
				}
			} else if fMatchValue, ok := matchValue.(float64); ok {
				if sDBField == "id" && fMatchValue == 0 { //添加这个条件是为了和之前提供给app开发人员使用的qry接口一致，即当id为0时查询所有记录
					continue
				}
				gormdb = gormdb.Where("`"+sDBField+"` = ? ", int(fMatchValue))
			} else {
				logger.Error("int类型的" + sJsonField + "字段的输入条件不合法！")
			}
		} else if sFieldType == "float" {
			if sMatchValue, ok := matchValue.(string); ok {
				if strings.HasPrefix(sMatchValue, ">=") || strings.HasPrefix(sMatchValue, "<=") {
					sRealMatchValue := strings.TrimSpace(sMatchValue[2:])
					if sRealMatchValue == "" {
						continue
					}
					iMatchValue, err2 := strconv.Atoi(sRealMatchValue)
					if err2 != nil {
						logger.Error(sFieldType + "类型的" + sJsonField + "字段的输入条件不合法！" + matchValue.(string))
					}
					gormdb = gormdb.Where("`"+sDBField+"` "+sMatchValue[0:2]+" ? ", iMatchValue)
				} else if strings.HasPrefix(sMatchValue, "=") || strings.HasPrefix(sMatchValue, ">") || strings.HasPrefix(sMatchValue, "<") {
					sRealMatchValue := strings.TrimSpace(sMatchValue[1:])
					if sRealMatchValue == "" {
						continue
					}
					iMatchValue, err2 := strconv.Atoi(sRealMatchValue)
					if err2 != nil {
						logger.Error(sFieldType + "类型的" + sJsonField + "字段的输入条件不合法！" + matchValue.(string))
					}
					gormdb = gormdb.Where("`"+sDBField+"` "+sMatchValue[0:1]+" ? ", iMatchValue)
				}
			} else if fMatchValue, ok := matchValue.(float64); ok {
				if sDBField == "id" { //添加这个条件是为了和之前提供给app开发人员使用的qry接口一致，即当id为0时查询所有记录
					if fMatchValue == 0 {
						continue
					}
				}
				gormdb = gormdb.Where("`"+sDBField+"` = ? ", int(fMatchValue))
			} else {
				logger.Error("int类型的" + sJsonField + "字段的输入条件不合法！")
			}
		} else if sFieldType == "time.Time" {
			sMatchValue, _ := matchValue.(string)
			if strings.HasPrefix(sMatchValue, ">=") || strings.HasPrefix(sMatchValue, "<=") {
				sRealMatchValue := strings.TrimSpace(sMatchValue[2:])
				if sRealMatchValue == "" {
					continue
				}
				gormdb = gormdb.Where("`"+sDBField+"` "+sMatchValue[0:2]+" ? ", sRealMatchValue)
			} else if strings.HasPrefix(sMatchValue, "=") || strings.HasPrefix(sMatchValue, ">") || strings.HasPrefix(sMatchValue, "<") {
				sRealMatchValue := strings.TrimSpace(sMatchValue[1:])
				if sRealMatchValue == "" {
					continue
				}
				gormdb = gormdb.Where("`"+sDBField+"` "+sMatchValue[0:1]+" ? ", sRealMatchValue)
			} else {
				gormdb = gormdb.Where("`"+sDBField+"` = ?", sMatchValue)
			}
		} else {
			gormdb = gormdb.Where("`"+sDBField+"` = ?", matchValue.(string))
		}
	}

	gormdb.Count(&totalcnt)

	if iPageSize != 0 {
		gormdb = gormdb.Limit(iPageSize)
		if iPageNum != 0 {
			iOffset := (iPageNum - 1) * iPageSize
			gormdb = gormdb.Offset(iOffset)
		}
	}

	if sOrder != "" {
		orderFieldArr := strings.Split(sOrder, ",")
		for _, oneOrderField := range orderFieldArr {
			sTmpOrderField := strings.Trim(oneOrderField, " ")
			if strings.HasPrefix(sTmpOrderField, "-") {
				sTmpOrderField = sTmpOrderField[1:]
				gormdb = gormdb.Order(sTmpOrderField + " desc")
			} else {
				gormdb = gormdb.Order(sTmpOrderField + " asc")
			}
		}
	}

	//结果
	typ := reflect.TypeOf(pModel)
	kd := typ.Kind() //获取到a对应的类别
	if kd == reflect.Ptr {
		typ = typ.Elem()
	}
	arrstuTyp := reflect.SliceOf(typ)

	v1 := reflect.New(arrstuTyp)
	rows = v1.Interface() //指针类型的
	gormdb = gormdb.Find(rows)
	if gormdb.Error != nil {
		err = gormdb.Error
		logger.Debug("查询失败!", gormdb.Error)
		return nil, 0, gormdb.Error
	}
	return
}
